# TenantManagementService 测试运行脚本
# 支持单元测试、集成测试、性能测试和覆盖率报告

param(
    [Parameter(Mandatory=$false)]
    [ValidateSet("Unit", "Integration", "Performance", "All", "Coverage")]
    [string]$TestType = "All",

    [Parameter(Mandatory=$false)]
    [string]$Filter,

    [Parameter(Mandatory=$false)]
    [switch]$NoCoverage,

    [Parameter(Mandatory=$false)]
    [switch]$NoClean,

    [Parameter(Mandatory=$false)]
    [switch]$Verbose,

    [Parameter(Mandatory=$false)]
    [int]$Timeout = 300
)

$ErrorActionPreference = "Stop"

# 脚本配置
$ProjectRoot = Split-Path -Parent $PSScriptRoot
$TestProjectRoot = Join-Path $ProjectRoot "test"
$TestResultsDir = Join-Path $TestProjectRoot "TestResults"
$CoverageDir = Join-Path $TestResultsDir "coverage"
$ReportsDir = Join-Path $TestResultsDir "reports"

# 创建必要的目录
function Ensure-Directory {
    param([string]$Path)
    if (-not (Test-Path $Path)) {
        New-Item -ItemType Directory -Path $Path -Force | Out-Null
        Write-Host "创建目录: $Path" -ForegroundColor Green
    }
}

function Write-Status {
    param([string]$Message, [string]$Level = "Info")
    $Colors = @{
        "Info" = "White"
        "Success" = "Green"
        "Warning" = "Yellow"
        "Error" = "Red"
    }
    Write-Host "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] $Message" -ForegroundColor $Colors[$Level]
}

function Initialize-TestEnvironment {
    Write-Status "初始化测试环境..."

    Ensure-Directory $TestResultsDir
    Ensure-Directory $CoverageDir
    Ensure-Directory $ReportsDir

    # 环境变量设置
    $env:ASPNETCORE_ENVIRONMENT = "Testing"
    $env:DOTNET_ENVIRONMENT = "Testing"

    Write-Status "测试环境初始化完成" "Success"
}

function Clean-TestResults {
    if ($NoClean) {
        Write-Status "跳过清理测试结果"
        return
    }

    Write-Status "清理测试结果..."

    if (Test-Path $TestResultsDir) {
        Remove-Item -Path $TestResultsDir -Recurse -Force
        Write-Status "已清理测试结果目录" "Success"
    }

    # 重新创建目录
    Ensure-Directory $TestResultsDir
    Ensure-Directory $CoverageDir
    Ensure-Directory $ReportsDir
}

function Run-UnitTests {
    Write-Status "运行单元测试..."

    $UnitProjects = @(
        "TenantManagementService.Domain.Tests",
        "TenantManagementService.Application.Tests"
    )

    foreach ($Project in $UnitProjects) {
        $ProjectPath = Join-Path $TestProjectRoot $Project
        $ProjectFile = Join-Path $ProjectPath "$Project.csproj"

        if (Test-Path $ProjectFile) {
            Write-Status "运行单元测试: $Project"

            $Arguments = @(
                "test", $ProjectFile,
                "--logger", "trx;LogFileName=$Project.trx",
                "--results-directory", $TestResultsDir,
                "--verbosity", "normal",
                "--no-build",
                "--configuration", "Release"
            )

            if ($Filter) {
                $Arguments += "--filter", $Filter
            }

            if ($Verbose) {
                $Arguments += "--verbosity", "detailed"
            }

            $env:CollectCoverage = "true"
            $env:CoverletOutputFormat = "cobertura,opencover,lcov"
            $env:CoverletOutput = Join-Path $CoverageDir "$Project.coverage"

            $Process = Start-Process -FilePath "dotnet" -ArgumentList $Arguments -NoNewWindow -PassThru -Wait
            $ExitCode = $Process.ExitCode

            if ($ExitCode -ne 0) {
                Write-Status "单元测试失败: $Project (退出代码: $ExitCode)" "Error"
                throw "单元测试失败"
            }

            Write-Status "单元测试完成: $Project" "Success"
        } else {
            Write-Status "单元测试项目不存在: $Project" "Warning"
        }
    }
}

function Run-IntegrationTests {
    Write-Status "运行集成测试..."

    $IntegrationProjects = @(
        "TenantManagementService.HttpApi.Host.Tests"
    )

    foreach ($Project in $IntegrationProjects) {
        $ProjectPath = Join-Path $TestProjectRoot $Project
        $ProjectFile = Join-Path $ProjectPath "$Project.csproj"

        if (Test-Path $ProjectFile) {
            Write-Status "运行集成测试: $Project"

            $Arguments = @(
                "test", $ProjectFile,
                "--logger", "trx;LogFileName=$Project.trx",
                "--results-directory", $TestResultsDir,
                "--verbosity", "normal",
                "--no-build",
                "--configuration", "Release"
            )

            if ($Filter) {
                $Arguments += "--filter", $Filter
            }

            if ($Verbose) {
                $Arguments += "--verbosity", "detailed"
            }

            $Process = Start-Process -FilePath "dotnet" -ArgumentList $Arguments -NoNewWindow -PassThru -Wait
            $ExitCode = $Process.ExitCode

            if ($ExitCode -ne 0) {
                Write-Status "集成测试失败: $Project (退出代码: $ExitCode)" "Error"
                throw "集成测试失败"
            }

            Write-Status "集成测试完成: $Project" "Success"
        } else {
            Write-Status "集成测试项目不存在: $Project" "Warning"
        }
    }
}

function Run-PerformanceTests {
    Write-Status "运行性能测试..."

    $PerformanceProject = "TenantManagementService.Performance.Tests"
    $ProjectPath = Join-Path $TestProjectRoot $PerformanceProject
    $ProjectFile = Join-Path $ProjectPath "$PerformanceProject.csproj"

    if (Test-Path $ProjectFile) {
        Write-Status "运行性能测试: $PerformanceProject"

        $Arguments = @(
            "test", $ProjectFile,
            "--logger", "trx;LogFileName=$PerformanceProject.trx",
            "--results-directory", $TestResultsDir,
            "--verbosity", "normal",
            "--no-build",
            "--configuration", "Release"
        )

        if ($Filter) {
            $Arguments += "--filter", $Filter
        }

        if ($Verbose) {
            $Arguments += "--verbosity", "detailed"
        }

        $Process = Start-Process -FilePath "dotnet" -ArgumentList $Arguments -NoNewWindow -PassThru -Wait
        $ExitCode = $Process.ExitCode

        if ($ExitCode -ne 0) {
            Write-Status "性能测试失败: $PerformanceProject (退出代码: $ExitCode)" "Error"
            throw "性能测试失败"
        }

        Write-Status "性能测试完成: $PerformanceProject" "Success"
    } else {
        Write-Status "性能测试项目不存在: $PerformanceProject" "Warning"
    }
}

function Merge-CoverageReports {
    if ($NoCoverage) {
        Write-Status "跳过覆盖率报告生成"
        return
    }

    Write-Status "合并覆盖率报告..."

    $CoverageFiles = Get-ChildItem -Path $CoverageDir -Filter "*.coverage" -ErrorAction SilentlyContinue

    if ($CoverageFiles.Count -eq 0) {
        Write-Status "没有找到覆盖率文件" "Warning"
        return
    }

    try {
        # 安装 reportgenerator 工具（如果未安装）
        $ToolInstalled = dotnet tool list -g | Select-String "dotnet-reportgenerator-globaltool"
        if (-not $ToolInstalled) {
            Write-Status "安装 ReportGenerator 工具..."
            dotnet tool install --global dotnet-reportgenerator-globaltool
        }

        $ReportArgs = @(
            "-reports", (Join-Path $CoverageDir "*.coverage"),
            "-targetdir", $ReportsDir,
            "-reporttypes", "Html;HtmlInline;Cobertura;Json",
            "-reporttitle", "TenantManagementService Coverage Report"
        )

        & dotnet reportgenerator @ReportArgs

        Write-Status "覆盖率报告已生成: $ReportsDir\index.html" "Success"

        # 输出覆盖率摘要
        $CoberturaFile = Join-Path $ReportsDir "Cobertura.xml"
        if (Test-Path $CoberturaFile) {
            $Xml = [xml](Get-Content $CoberturaFile)
            $LineCoverage = $Xml.coverage.coverage-rate
            $BranchCoverage = $Xml.coverage.branch-rate

            Write-Status "代码覆盖率摘要:" "Info"
            Write-Status "  行覆盖率: $([math]::Round($LineCoverage * 100, 2))%" "Info"
            Write-Status "  分支覆盖率: $([math]::Round($BranchCoverage * 100, 2))%" "Info"
        }
    }
    catch {
        Write-Status "生成覆盖率报告失败: $($_.Exception.Message)" "Warning"
    }
}

function Generate-TestSummary {
    Write-Status "生成测试摘要..."

    $SummaryFile = Join-Path $TestResultsDir "test-summary.json"
    $Summary = @{
        "timestamp" = Get-Date -Format "yyyy-MM-ddTHH:mm:ssZ"
        "testType" = $TestType
        "filter" = $Filter
        "timeout" = $Timeout
        "projects" = @()
    }

    # 分析测试结果文件
    $TrxFiles = Get-ChildItem -Path $TestResultsDir -Filter "*.trx" -ErrorAction SilentlyContinue

    foreach ($TrxFile in $TrxFiles) {
        $Xml = [xml](Get-Content $TrxFile.FullName)
        $TestRun = $Xml.TestRun

        $Summary.projects += @{
            "name" = $TrxFile.BaseName
            "total" = $TestRun.TotalTests
            "passed" = $TestRun.PassedTests
            "failed" = $TestRun.FailedTests
            "skipped" = $TestRun.SkippedTests
            "duration" = $TestRun.Times.Duration
            "outcome" = if ($TestRun.Outcome -eq "Completed") { "Passed" } else { "Failed" }
        }
    }

    $Summary | ConvertTo-Json -Depth 10 | Out-File -FilePath $SummaryFile -Encoding UTF8
    Write-Status "测试摘要已保存: $SummaryFile" "Success"

    # 输出摘要信息
    $TotalTests = $Summary.projects | ForEach-Object { $_.total } | Measure-Object -Sum
    $TotalPassed = $Summary.projects | ForEach-Object { $_.passed } | Measure-Object -Sum
    $TotalFailed = $Summary.projects | ForEach-Object { $_.failed } | Measure-Object -Sum

    Write-Status "测试执行摘要:" "Info"
    Write-Status "  总测试数: $($TotalTests.Sum)" "Info"
    Write-Status "  通过: $($TotalPassed.Sum)" "Success"
    Write-Status "  失败: $($TotalFailed.Sum)" "Error"
    Write-Status "  成功率: $([math]::Round(($TotalPassed.Sum / $TotalTests.Sum) * 100, 2))%" "Info"
}

function Invoke-TestsWithTimeout {
    param([scriptblock]$ScriptBlock)

    $Job = Start-Job -ScriptBlock $ScriptBlock
    $Completed = Wait-Job -Job $Job -Timeout $Timeout

    if (-not $Completed) {
        Write-Status "测试执行超时 ($Timeout 秒)" "Error"
        Remove-Job -Job $Job -Force
        throw "测试执行超时"
    }

    $Result = Receive-Job -Job $Job
    Remove-Job -Job $Job

    if ($Result.Exception) {
        throw $Result.Exception
    }
}

# 主执行逻辑
try {
    Initialize-TestEnvironment
    Clean-TestResults

    $ScriptBlock = {
        param($TestType, $Filter, $Verbose)

        switch ($TestType) {
            "Unit" {
                Run-UnitTests
            }
            "Integration" {
                Run-IntegrationTests
            }
            "Performance" {
                Run-PerformanceTests
            }
            "All" {
                Run-UnitTests
                Run-IntegrationTests
                Run-PerformanceTests
            }
            "Coverage" {
                Run-UnitTests
                Run-IntegrationTests
                Merge-CoverageReports
            }
        }
    }

    Write-Status "开始运行测试类型: $TestType"

    Invoke-TestsWithTimeout -ScriptBlock $ScriptBlock -ArgumentList $TestType, $Filter, $Verbose

    if ($TestType -eq "All" -or $TestType -eq "Coverage") {
        Merge-CoverageReports
    }

    Generate-TestSummary

    Write-Status "所有测试执行完成!" "Success"

    # 显示报告位置
    Write-Status "测试报告位置:" "Info"
    Write-Status "  测试结果: $TestResultsDir" "Info"
    Write-Status "  覆盖率报告: $ReportsDir\index.html" "Info"

}
catch {
    Write-Status "测试执行失败: $($_.Exception.Message)" "Error"
    Write-Status "详细信息: $($_.Exception.StackTrace)" "Error"
    exit 1
}